<?php
declare (strict_types=1);

namespace app\Common\Middleware;

use app\Common\Decorators\JWT;
use app\Common\Error\ApiErrorDesc;
use app\Common\Exception\ApiException;

use think\facade\Cache;
use think\facade\Db;

class  AppAuth
{
  /**
   * 当前模块名
   * @var string
   */
  protected $module;

  /**
   * 当前控制器名
   * @var string
   */
  protected $controller;

  /**
   * 当前操作名
   * @var string
   */
  protected $action;

  protected $rules; //用户拥有的权限id

  /**
   * 处理请求
   * @param $request
   * @param \Closure $next
   * @return mixed|void
   */
  public function handle($request, \Closure $next)
  {
    //
    $token = JWT::verifyToken($request->header('token'));

    $this->setTheme($request);//获取模块、控制器、操作方法

    $userInfo = json_decode($token['data']);

    $url = $this->controller . '/' . $this->action;

    if (!isset($userInfo->worker_id)) {
      throw new ApiException(ApiErrorDesc::LOGIN_USER_ERROR);
    }

    $workerId = $userInfo->worker_id;//用户身份id

//    self::checkExpire($userInfo);//验证是否登入过期

    $request->ip = $request->header('x-real-ip') ?? $request->ip();//客户端ip
    $request->scheme = $request->header('x-real-scheme') ?? $request->scheme();//客户端请求http协议
//        $cacheName = $uid . '_' . $url . '_' . ($request->server()['QUERY_STRING'] ?? null);
//    $cacheName = $workerId . '_worker_' . $url;
    $cacheName = $workerId . '_worker_' . $request->server('REQUEST_URI');
    if (!in_array($request->ip, ['127.0.0.1', '::1'])) {
      if (Cache::store('redis')->get($cacheName)) {

        throw new ApiException(ApiErrorDesc::DATA_PROCESSED);
      } else {
//                $second = in_array($request->method(), ['PUT', 'POST']) ? 5 : 1;//5秒  1秒
//                //缓存$second秒后过期
//                Cache::store('redis')->set($cacheName, 1, $second);
        Cache::store('redis')->set($cacheName, 1, 15);
      }
    }
    $request->cacheName = $cacheName;

    $allow_module_name = ['pay']; //放行模块名称
    $allow_controller_name = []; //放行控制器名称

    $allow_action_name = ['personal', 'edit', 'delete', 'save', 'audit', 'read', 'get'];//放行操作

    $module = in_array($request->module, $allow_module_name);//放行模块
    $controller = in_array($request->controller, $allow_controller_name);//放行控制器
    $action = in_array($request->action, $allow_action_name);//放行操作

    //逻辑处理
//    $request->isMobile()
//    $auths = $this->check($url, $uid, $userInfo->is_cuadmin);
//    if ($uid <> 1 && !$module && !$controller && !$action && !$auths && strpos($request->rule()->getRoute(), 'xtsb/') !== false) { //非超级管理员
//      throw new ApiException(ApiErrorDesc::RULE_ERROR);
//    }

    $request->userInfo = $userInfo;
    $request->rules = $this->rules;//Db::name('auth_rule')->whereIn('id', $rules)->column('url')

    $request->moduleName = $this->module;//模块名
    $request->controllerName = $this->controller;//控制器名
    $request->actionName = $this->action;//操作方法

    return $next($request);
  }

  //鉴权
  private function check($url, $uid, $isCuadmin)
  {
    if ($uid == 1) {

      $this->rules = Db::name('auth_rule')
        ->whereNotNull('url')
//        ->whereRaw('LENGTH(TRIM(url))>0')
        ->column('url');
    } else {

      if ($isCuadmin) { //企业管理员
        $rulesInfo = Db::name('staff_access')->alias('u')
          ->field('g.rules')
          ->leftJoin('company c', 'c.id=u.cuid')
          ->leftJoin('auth_group g', 'g.id=c.group_id')
          ->where('u.id', $uid)
          ->json(['rules'])
          ->find()//          ->value('g.rules')
        ;
        $rules = isset($rulesInfo['rules']) ? $rulesInfo['rules'] : [];
      } else {
        $rulesInfo = Db::name('staff_access')->alias('u')
          ->field('g.rules drules,t4.rules urules')
          ->leftJoin('dmp g', 'g.id=u.dmp_id')
          ->leftJoin('staff t3', 't3.id=u.staff_id')
          ->leftJoin('user t4', 't4.uid=t3.uid')
          ->where('u.id', $uid)
          ->json(['drules', 'urules'])
          ->find();
        $rules = array_merge(isset($rulesInfo['drules']) ? $rulesInfo['drules'] : [],
          isset($rulesInfo['urules']) ? $rulesInfo['urules'] : []);
      }

      if (isset($rules)) {
        $this->rules = Db::name('auth_rule')->whereIn('id', $rules)
          ->whereOr('is_admin', 2)//开放权限
          ->whereNotNull('url')
//          ->whereRaw('LENGTH(TRIM(url))>0')
          ->column('url');

//        $rules_arr = explode(',', $rules);

        $rule_id = Db::name('auth_rule')->where('url', $url)->value('id');
//dd($rules);
        if (!in_array($rule_id, $rules)) {

          return false;
        }

      } else {
        //未设置岗位
        $this->rules = [];

        return false;
      }


    }


    return true;
  }

  /**
   * Notes:获取模块名、控制器名、操作方法名
   * author: chen
   * DateTime: 2022/2/9 9:13
   * @param $request
   */
  private function setTheme($request)
  {
    //获取控制器名称
    $route = $request->rule()->getName();

    if ($route === 'app\Http\:module_name\Controllers\:controller_nameController@:action_name') {
      //动态路由
      $info = explode('/', str_replace('/api/v1/xtsb/', '', $request->server()['REDIRECT_URL'] ?? $request->server()['PATH_INFO']));
      $this->action = $info[1];
      $this->controller = $info[0];
      $this->module = $info[2];
    } else if (strpos($route, '/')) {
      //资源路由
      $info = explode('\\', str_replace('/', '\\', $route));
      $this->action = $info[5];
      $this->controller = str_replace('Controller', '', $info[4]);
      $this->module = $info[2];
    } else if (strpos($route, '@')) {
      //操作方法路由
      $info = explode('\\', str_replace('@', '\\', $route));
      $this->action = $info[5];
      $this->controller = str_replace('Controller', '', $info[4]);
      $this->module = $info[2];
    } else {

      throw new ApiException(ApiErrorDesc::TOKEN_REQUIRE);
    }
  }

  /**
   * Notes:登入是否过期
   * author: chen
   * DateTime: 2022/9/28 10:26
   * @param $loginTime
   * @param $uuid
   * @param int $expireTime 过期时间 单位：h
   * @return bool
   */
  private function checkExpire($userInfo, $expireTime = 8)
  {

    $loginTime = $userInfo->login_time;
    $uuid = $userInfo->uuid;
    $loginExpire = $userInfo->login_expire ?? true;//是否验证登入超时

    $user = Db::name('user')->field('sign_time,cuid,sign_time_m')->where('uid', $uuid)->find();

    $cuid = $user['cuid'];

    //测试账号/超时验证开关=false 不验证
    if ($cuid == 14 || !$loginExpire) {
      return true;
    }

    if (request()->isMobile()) {
      //移动端登入
      $userLoginTime = $user['sign_time_m'];
      //$loginTime空
      if (empty($loginTime) || $loginTime < $userLoginTime) {
        throw new ApiException(ApiErrorDesc::LOGIN_EXPIRE);
      }
    } else {
      //PC端登入
      $userLoginTime = $user['sign_time'];
      //$loginTime空 或 超过$expireTime 小时 则退出登入
      if (
        empty($loginTime) ||
        $loginTime < $userLoginTime ||
        (time() - strtotime($loginTime) > $expireTime * 60 * 60)
      ) {
        throw new ApiException(ApiErrorDesc::LOGIN_EXPIRE);
      }
    }


    return true;
  }
}

